/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <ohaudio/native_audiocapturer.h>
#include <ohaudio/native_audiorenderer.h>
#include <ohaudio/native_audiostreambuilder.h>
#include <ohaudio/native_audiostream_base.h>
#include "oh_aaudio.h"
#include <hilog/log.h>
#include <stdio.h>

struct ma_AAudioStreamBuilder_t {
    int32_t deviceId;
    OH_AudioStreamBuilder *builder;
    ma_aaudio_direction_t direction;
    int32_t numFrames;
    int32_t capacityInFrames;

    void *pUserData;
    void *pUserError;
    ma_AAudioStream_dataCallback dataCallback;
    ma_AAudioStream_errorCallback errorCallback;
};

struct ma_AAudioStream_t {
    ma_aaudio_direction_t direction;
    union AudioStream {
        OH_AudioRenderer *renderer;
        OH_AudioCapturer *capturer;
    } stream;
    ma_AAudioStreamBuilder_t *builder;
};

#define OHOS_LOG_BUF_SIZE 1024
#define OHOS_LOG_TAG      "rive_text"
enum OhosLogLevel { IL_INFO, IL_DEBUG, IL_WARN, IL_ERROR, IL_FATAL };
void __ohos_log_print(enum OhosLogLevel level, const char *tag, const char *fmt, ...)
{
    char buf[OHOS_LOG_BUF_SIZE] = {0};
    va_list arg;
    va_start(arg, fmt);
    vsnprintf(buf, OHOS_LOG_BUF_SIZE, fmt, arg);

    switch (level) {
        case IL_INFO:
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
        case IL_DEBUG:
            OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
        case IL_WARN:
            OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
        case IL_ERROR:
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
        case IL_FATAL:
            OH_LOG_Print(LOG_APP, LOG_FATAL, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
        default:
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, tag, "%{public}s", buf);
            break;
    }
    va_end(arg);
}

#define LOGI(...) __ohos_log_print(IL_INFO, OHOS_LOG_TAG, __VA_ARGS__)
#define LOGW(...) __ohos_log_print(IL_WARN, OHOS_LOG_TAG, __VA_ARGS__)
#define LOGE(...) __ohos_log_print(IL_ERROR, OHOS_LOG_TAG, __VA_ARGS__)
#define LOGF(...) __ohos_log_print(IL_FATAL, OHOS_LOG_TAG, __VA_ARGS__)
#define LOGD(...) __ohos_log_print(IL_DEBUG, OHOS_LOG_TAG, __VA_ARGS__)

ma_aaudio_result_t AAudio_createStreamBuilder(ma_AAudioStreamBuilder **ppBuilder)
{
    ma_AAudioStreamBuilder_t *streamBuilder = new ma_AAudioStreamBuilder_t();
    streamBuilder->numFrames = 0;
    streamBuilder->capacityInFrames = 0;
    *ppBuilder = static_cast<ma_AAudioStreamBuilder *>(streamBuilder);
    LOGD("OH_AudioStreamBuilder_Create");
    return MA_AAUDIO_OK;
}

ma_aaudio_result_t AAudioStreamBuilder_delete(ma_AAudioStreamBuilder *pBuilder)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return MA_AAUDIO_OK;
    }
    LOGD("OH_AudioStreamBuilder_Destroy- Test delete");
    return MA_AAUDIO_OK;
}

void AAudioStreamBuilder_setDeviceId(ma_AAudioStreamBuilder *pBuilder, int32_t deviceId)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setDeviceId");
    mBuilder->deviceId = deviceId;
}

void AAudioStreamBuilder_setDirection(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_direction_t direction)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setDirection");
    OH_AudioStream_Result result;
    mBuilder->direction = direction;
    if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioStreamBuilder_Create(&mBuilder->builder, AUDIOSTREAM_TYPE_RENDERER);
    } else {
        result = OH_AudioStreamBuilder_Create(&mBuilder->builder, AUDIOSTREAM_TYPE_CAPTURER);
    }
    if (result != 0) {
        LOGE("OH_AudioStreamBuilder_Create failed, %d", result);
    }
    if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        OH_AudioStreamBuilder_SetEncodingType(mBuilder->builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
        OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_MUSIC);
    } else {
        OH_AudioStreamBuilder_SetEncodingType(mBuilder->builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
        OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
    }
}

void AAudioStreamBuilder_setSharingMode(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_sharing_mode_t sharingMode) {}

void AAudioStreamBuilder_setFormat(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_format_t format)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    OH_AudioStream_SampleFormat ohFormat;
    switch (format) {
        case MA_AAUDIO_FORMAT_PCM_I16:
            ohFormat = AUDIOSTREAM_SAMPLE_S16LE;
            break;
        case MA_AAUDIO_FORMAT_PCM_FLOAT:
            ohFormat = AUDIOSTREAM_SAMPLE_F32LE;
            break;
        default:
            ohFormat = AUDIOSTREAM_SAMPLE_S16LE;
            break;
    }
    LOGD("OH_AudioStreamBuilder_SetSampleFormat, format: %d -> %d", format, ohFormat);
    OH_AudioStreamBuilder_SetSampleFormat(mBuilder->builder, ohFormat);
}

void AAudioStreamBuilder_setChannelCount(ma_AAudioStreamBuilder *pBuilder, int32_t channelCount)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("OH_AudioStreamBuilder_SetChannelCount, channel: %d -> %d", channelCount, channelCount);
    OH_AudioStreamBuilder_SetChannelCount(mBuilder->builder, channelCount);
}

void AAudioStreamBuilder_setSampleRate(ma_AAudioStreamBuilder *pBuilder, int32_t sampleRate)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    int rate = sampleRate;
    LOGD("OH_AudioStreamBuilder_SetSamplingRate, sample rate: %d -> %d", sampleRate, rate);
    OH_AudioStreamBuilder_SetSamplingRate(mBuilder->builder, rate);
}

void AAudioStreamBuilder_setBufferCapacityInFrames(ma_AAudioStreamBuilder *pBuilder, int32_t numFrames)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setBufferCapacityInFrames, num frames: %d -> %d", numFrames, numFrames);
    mBuilder->capacityInFrames = numFrames;
}

void AAudioStreamBuilder_setFramesPerDataCallback(ma_AAudioStreamBuilder *pBuilder, int32_t numFrames)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    mBuilder->numFrames = numFrames;
    LOGD("AAudioStreamBuilder_setFramesPerDataCallback, num frames: %d -> %d", numFrames, numFrames);
}

void AAudioStreamBuilder_setDataCallback(
    ma_AAudioStreamBuilder *pBuilder, ma_AAudioStream_dataCallback callback, void *pUserData)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    mBuilder->pUserData = pUserData;
    mBuilder->dataCallback = callback;
}

void AAudioStreamBuilder_setErrorCallback(
    ma_AAudioStreamBuilder *pBuilder, ma_AAudioStream_errorCallback callback, void *pUserData)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    mBuilder->pUserError = pUserData;
    mBuilder->errorCallback = callback;
}

void AAudioStreamBuilder_setPerformanceMode(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_performance_mode_t mode)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    OH_AudioStream_LatencyMode latencyMode;
    switch (mode) {
        case MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
            latencyMode = AUDIOSTREAM_LATENCY_MODE_FAST;
            break;
        case MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
            latencyMode = AUDIOSTREAM_LATENCY_MODE_NORMAL;
            break;
        default:
            latencyMode = AUDIOSTREAM_LATENCY_MODE_NORMAL;
            break;
    }
    LOGD("OH_AudioStreamBuilder_SetLatencyMode, mode: %d -> %d", mode, latencyMode);
    OH_AudioStreamBuilder_SetLatencyMode(mBuilder->builder, latencyMode);
}

void AAudioStreamBuilder_setUsage(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_usage_t contentType)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setUsage, usage: %d", contentType);

    switch (contentType) {
        case MA_AAUDIO_USAGE_MEDIA:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_MUSIC);
            }
            break;
        case MA_AAUDIO_USAGE_VOICE_COMMUNICATION:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_VOICE_COMMUNICATION);
            } else {
                OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATION);
            }
            break;
        case MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_ALARM);
            }
            break;
        case MA_AAUDIO_USAGE_ALARM:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_ALARM);
            }
            break;
        case MA_AAUDIO_USAGE_NOTIFICATION:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_NOTIFICATION);
            }
            break;
        case MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_RINGTONE);
            }
            break;
        case MA_AAUDIO_USAGE_NOTIFICATION_EVENT:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_VOICE_MESSAGE);
            }
            break;
        case MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_ACCESSIBILITY);
            }
            break;
        case MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_NAVIGATION);
            }
            break;
        case MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION:
            break;
        case MA_AAUDIO_USAGE_GAME:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_GAME);
            }
            break;
        case MA_AAUDIO_USAGE_ASSISTANT:
            if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
                OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_VOICE_ASSISTANT);
            } else {
                OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_RECOGNITION);
            }
            break;
        case MA_AAUDIO_SYSTEM_USAGE_EMERGENCY:
            // ohUsage = AUDIOSTREAM_USAGE_UNKNOWN;
            break;
        case MA_AAUDIO_SYSTEM_USAGE_SAFETY:
            // ohUsage = AUDIOSTREAM_USAGE_UNKNOWN;
            break;
        case MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS:
            // ohUsage = AUDIOSTREAM_USAGE_UNKNOWN;
            break;
        case MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT:
            // ohUsage = AUDIOSTREAM_USAGE_UNKNOWN;
            break;
        default:
            // ohUsage = AUDIOSTREAM_USAGE_UNKNOWN; // 默认值
            break;
    }
}

void AAudioStreamBuilder_setContentType(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_content_type_t contentType)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    switch (contentType) {
        case MA_AAUDIO_CONTENT_TYPE_SPEECH:
            break;
        case MA_AAUDIO_CONTENT_TYPE_MUSIC:
            break;
        case MA_AAUDIO_CONTENT_TYPE_MOVIE:
            break;
        case MA_AAUDIO_CONTENT_TYPE_SONIFICATION:
            break;
        default:
            break;
    }
    LOGD("AAudioStreamBuilder_setContentType, type: %d", contentType);
}

void AAudioStreamBuilder_setInputPreset(ma_AAudioStreamBuilder *pBuilder, ma_aaudio_input_preset_t inputPreset)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setInputPreset, type: %d", inputPreset);
    switch (inputPreset) {
        case MA_AAUDIO_INPUT_PRESET_GENERIC:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
            break;
        case MA_AAUDIO_INPUT_PRESET_CAMCORDER:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_CAMCORDER);
            break;
        case MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_RECOGNITION);
            break;
        case MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATION);
            break;
        case MA_AAUDIO_INPUT_PRESET_UNPROCESSED:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_UNPROCESSED);
            break;
        case MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_VOICE_MESSAGE);
            break;
        default:
            OH_AudioStreamBuilder_SetCapturerInfo(mBuilder->builder, AUDIOSTREAM_SOURCE_TYPE_INVALID);
            break;
    }
}

void AAudioStreamBuilder_setAllowedCapturePolicy(
    ma_AAudioStreamBuilder *pBuilder, ma_aaudio_allowed_capture_policy_t policy)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return;
    }
    LOGD("AAudioStreamBuilder_setAllowedCapturePolicy, policy: %d", policy);
    switch (policy) {
        case MA_AAUDIO_ALLOW_CAPTURE_BY_ALL:
            OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_MUSIC);
            break;
        case MA_AAUDIO_ALLOW_CAPTURE_BY_SYSTEM:
            OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_VOICE_COMMUNICATION);
            break;
        case MA_AAUDIO_ALLOW_CAPTURE_BY_NONE:
            OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_VOICE_ASSISTANT);
            break;
        default:
            OH_AudioStreamBuilder_SetRendererInfo(mBuilder->builder, AUDIOSTREAM_USAGE_MUSIC);
            break;
    }
}

static int32_t GetBytesPerframe(ma_AAudioStream_t *mStream)
{
    ma_aaudio_format_t format = AAudioStream_getFormat(mStream);
    int32_t channelCount = AAudioStream_getChannelCount(mStream);

    int32_t frameSize = 0;
    switch (format) {
        case MA_AAUDIO_FORMAT_PCM_I16:
            frameSize = channelCount * 2;
            break;
        case MA_AAUDIO_FORMAT_PCM_FLOAT:
            frameSize = channelCount * 4;
            break;
        default:
            frameSize = channelCount * 2;
            break;
    }
    return frameSize;
}

static OH_AudioData_Callback_Result AudioRendererOnWriteData(
    OH_AudioRenderer *renderer, void *userData, void *audioData, int32_t audioDataSize)
{
    ma_AAudioStream_t *stream = static_cast<ma_AAudioStream_t *>(userData);
    if (stream == nullptr || stream->builder == nullptr) {
        LOGE("stream is nullptr");
        return AUDIO_DATA_CALLBACK_RESULT_INVALID;
    }
    int32_t frameSize = GetBytesPerframe(stream);
    int32_t frameCount = audioDataSize / frameSize;
    // LOGD("AudioRenderer OnWriteData: frameSize: %d, frameCount: %d, totalSize: %d", frameSize, frameCount,
    //     audioDataSize);

    stream->builder->dataCallback(stream, stream->builder->pUserData, audioData, frameCount);
    return AUDIO_DATA_CALLBACK_RESULT_VALID;
}

static int32_t AudioRendererOnError(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error)
{
    ma_AAudioStream_t *stream = static_cast<ma_AAudioStream_t *>(userData);
    if (stream == nullptr || stream->builder == nullptr) {
        LOGE("stream is nullptr");
        return 0;
    }
    LOGD("AudioRenderer OnError: %d", error);
    stream->builder->errorCallback(stream, stream->builder->pUserError, error);
    return 0;
}

static void AudioRendererOnError2(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error)
{
    (void)AudioRendererOnError(renderer, userData, error);
}

static int32_t AudioRendererOnInterruptEvent(
    OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
    LOGD("AudioRenderer OnInterrupt, type: %d, hint: %d", type, hint);
    return 0;
}

static void AudioRendererOnInterruptEvent2(
    OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
    (void)AudioRendererOnInterruptEvent(renderer, userData, type, hint);
}

static int32_t CapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t length)
{
    ma_AAudioStream_t *stream = static_cast<ma_AAudioStream_t *>(userData);
    if (stream == nullptr || stream->builder == nullptr) {
        LOGE("stream is nullptr");
        return 0;
    }
    int32_t frameSize = GetBytesPerframe(stream);
    int32_t frameCount = length / frameSize;
    stream->builder->dataCallback(stream, stream->builder->pUserData, buffer, frameCount);
    return 0;
}

static int32_t CapturerOnError(OH_AudioCapturer *capturer, void *userData, OH_AudioStream_Result error)
{
    ma_AAudioStream_t *stream = static_cast<ma_AAudioStream_t *>(userData);
    if (stream == nullptr || stream->builder == nullptr) {
        LOGE("stream is nullptr");
        return 0;
    }
    LOGD("AudioCapturer OnError: %d", error);
    stream->builder->errorCallback(stream, stream->builder->pUserError, error);
    return 0;
}

static int32_t CapturerOnInterruptEvent(
    OH_AudioCapturer *capturer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
    LOGD("AudioCapturer OnInterrupt, type: %d, hint: %d", type, hint);
    return 0;
}

ma_aaudio_result_t AAudioStreamBuilder_openStream(ma_AAudioStreamBuilder *pBuilder, ma_AAudioStream **ppStream)
{
    ma_AAudioStreamBuilder_t *mBuilder = static_cast<ma_AAudioStreamBuilder_t *>(pBuilder);
    if (mBuilder == nullptr) {
        return -1;
    }
    LOGD("AAudioStreamBuilder_openStream");
    if (ppStream == nullptr) {
        LOGE("ppStream is nullptr");
        return -2;
    }
    OH_AudioStream_Result result;
    ma_AAudioStream_t *stream = new ma_AAudioStream_t;
    stream->direction = mBuilder->direction;
    stream->builder = mBuilder;
    *ppStream = stream;

    if (mBuilder->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        OH_AudioRenderer_Callbacks callbacks = {
            .OH_AudioRenderer_OnWriteData = nullptr,
            .OH_AudioRenderer_OnStreamEvent = nullptr,
            .OH_AudioRenderer_OnInterruptEvent = AudioRendererOnInterruptEvent,
            .OH_AudioRenderer_OnError = AudioRendererOnError,
        };
        result = OH_AudioStreamBuilder_SetRendererCallback(mBuilder->builder, callbacks, stream);
        OH_AudioStreamBuilder_SetRendererWriteDataCallback(mBuilder->builder, AudioRendererOnWriteData, stream);
        // OH_AudioStreamBuilder_SetRendererErrorCallback(mBuilder->builder, AudioRendererOnError2, stream);
        // OH_AudioStreamBuilder_SetRendererInterruptCallback(mBuilder->builder, AudioRendererOnInterruptEvent2,
        // stream);
        result = OH_AudioStreamBuilder_GenerateRenderer(mBuilder->builder, &stream->stream.renderer);

        // OH_AudioStreamBuilder_SetRendererWriteDataCallback(mBuilder->builder, AudioRendererOnWriteData, stream);
        // OH_AudioStreamBuilder_SetRendererErrorCallback(mBuilder->builder, AudioRendererOnError, steam);

        LOGD("Renderer set callbacks, %d", result);
    } else {
        OH_AudioCapturer_Callbacks callbacks;
        callbacks.OH_AudioCapturer_OnReadData = CapturerOnReadData;
        callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;
        callbacks.OH_AudioCapturer_OnInterruptEvent = CapturerOnInterruptEvent;
        callbacks.OH_AudioCapturer_OnError = CapturerOnError;
        result = OH_AudioStreamBuilder_SetCapturerCallback(mBuilder->builder, callbacks, stream);
        result = OH_AudioStreamBuilder_GenerateCapturer(mBuilder->builder, &stream->stream.capturer);
        // OH_AudioStreamBuilder_SetCapturerReadDataCallback(mBuilder->builder, CapturerOnReadData, stream);
        // OH_AudioStreamBuilder_SetCapturerErrorCallback(mBuilder->builder, CapturerOnError, stream);
    }
    if (result != AUDIOSTREAM_SUCCESS) {
        LOGE("Open stream failed, %d", result);
        delete stream;
        *ppStream = nullptr;
        return result;
    }
    OH_AudioStreamBuilder_SetFrameSizeInCallback(mBuilder->builder, GetBytesPerframe(stream));
    return MA_AAUDIO_OK;
}

ma_aaudio_result_t AAudioStream_close(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return -1;
    }
    OH_AudioStream_Result result;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_Release(mStream->stream.renderer);
    } else {
        result = OH_AudioCapturer_Release(mStream->stream.capturer);
    }
    LOGD("AAudioStreamBuilder_closeStream, result: %d", result);
    ma_AAudioStreamBuilder_t *builder = mStream->builder;
    mStream->builder = nullptr;
    delete mStream;
    if (builder) {
        OH_AudioStreamBuilder_Destroy(builder->builder);
        delete builder;
    }
    return result;
}

ma_aaudio_stream_state_t OhStateToAAudioState(OH_AudioStream_State ohState)
{
    switch (ohState) {
        case AUDIOSTREAM_STATE_INVALID:
            return MA_AAUDIO_STREAM_STATE_UNKNOWN; // 无效状态映射为未知状态

        case AUDIOSTREAM_STATE_NEW:
            return MA_AAUDIO_STREAM_STATE_UNINITIALIZED; // 新创建状态映射为未初始化

        case AUDIOSTREAM_STATE_PREPARED:
            return MA_AAUDIO_STREAM_STATE_OPEN; // 准备状态映射为打开状态

        case AUDIOSTREAM_STATE_RUNNING:
            return MA_AAUDIO_STREAM_STATE_STARTED; // 运行状态映射为已开始

        case AUDIOSTREAM_STATE_STOPPED:
            return MA_AAUDIO_STREAM_STATE_STOPPED; // 停止状态映射为已停止

        case AUDIOSTREAM_STATE_RELEASED:
            return MA_AAUDIO_STREAM_STATE_CLOSED; // 释放状态映射为已关闭

        case AUDIOSTREAM_STATE_PAUSED:
            return MA_AAUDIO_STREAM_STATE_PAUSED; // 暂停状态映射为已暂停

        default:
            return MA_AAUDIO_STREAM_STATE_UNKNOWN; // 未知状态映射为未知
    }
}

ma_aaudio_stream_state_t AAudioStream_getState(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return -1;
    }
    OH_AudioStream_Result result;
    OH_AudioStream_State state;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_GetCurrentState(mStream->stream.renderer, &state);
    } else {
        result = OH_AudioCapturer_GetCurrentState(mStream->stream.capturer, &state);
    }
    if (result != AUDIOSTREAM_SUCCESS) {
        return AUDIOSTREAM_STATE_INVALID;
    }
    return OhStateToAAudioState(state);
}

ma_aaudio_result_t AAudioStream_waitForStateChange(ma_AAudioStream *pStream, ma_aaudio_stream_state_t inputState,
    ma_aaudio_stream_state_t *pNextState, int64_t timeoutInNanoseconds)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return -1;
    }
    LOGD("AAudioStream_waitForStateChange, state: %d", inputState);
    ma_aaudio_stream_state_t currentState = AAudioStream_getState(pStream);
    int64_t pollInterval = 10000000; // 10ms
    int64_t elapsed = 0;

    while (timeoutInNanoseconds < 0 || elapsed < timeoutInNanoseconds) {
        struct timespec ts = {0, pollInterval};
        nanosleep(&ts, NULL);

        currentState = AAudioStream_getState(pStream);
        if (currentState != inputState) {
            *pNextState = currentState;
            return MA_AAUDIO_OK;
        }

        elapsed += pollInterval;
        if (timeoutInNanoseconds > 0 && elapsed > timeoutInNanoseconds) {
            break;
        }
    }
    *pNextState = currentState;
    return MA_AAUDIO_OK;
}

ma_aaudio_format_t AAudioStream_getFormat(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return MA_AAUDIO_FORMAT_PCM_I16;
    }
    OH_AudioStream_Result result;
    OH_AudioStream_SampleFormat format;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_GetSampleFormat(mStream->stream.renderer, &format);
    } else {
        result = OH_AudioCapturer_GetSampleFormat(mStream->stream.capturer, &format);
    }
    if (result != AUDIOSTREAM_SUCCESS) {
        LOGE("GetSampleFormat failed, %d", result);
        return MA_AAUDIO_FORMAT_PCM_I16;
    }
    if (format == AUDIOSTREAM_SAMPLE_F32LE) {
        return MA_AAUDIO_FORMAT_PCM_FLOAT;
    } else {
        return MA_AAUDIO_FORMAT_PCM_I16;
    }
}

int32_t AAudioStream_getChannelCount(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    int channelCount = 2;
    if (mStream == nullptr) {
        return channelCount;
    }
    OH_AudioStream_Result result;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_GetChannelCount(mStream->stream.renderer, &channelCount);
    } else {
        result = OH_AudioCapturer_GetChannelCount(mStream->stream.capturer, &channelCount);
    }
    return channelCount;
}

int32_t AAudioStream_getSampleRate(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    OH_AudioStream_Result result;
    int sampleRate = 48000;
    if (mStream == nullptr) {
        return sampleRate;
    }

    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_GetSamplingRate(mStream->stream.renderer, &sampleRate);
    } else {
        result = OH_AudioCapturer_GetSamplingRate(mStream->stream.capturer, &sampleRate);
    }
    return sampleRate;
}

int32_t AAudioStream_getBufferCapacityInFrames(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    OH_AudioStream_Result result = AUDIOSTREAM_SUCCESS;
    if (mStream == nullptr || mStream->builder == nullptr) {
        return 0;
    }
    return mStream->builder->capacityInFrames;
}

int32_t AAudioStream_getFramesPerDataCallback(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    OH_AudioStream_Result result;
    if (mStream == nullptr) {
        return 0;
    }

    int frames = 0;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_GetFrameSizeInCallback(mStream->stream.renderer, &frames);
    } else {
        result = OH_AudioCapturer_GetFrameSizeInCallback(mStream->stream.capturer, &frames);
    }
    return frames;
}

int32_t AAudioStream_getFramesPerBurst(ma_AAudioStream *pStream)
{
    LOGD("AAudioStream_getFramesPerBurst, %d", 0);
}

ma_aaudio_result_t AAudioStream_requestStart(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return -1;
    }
    OH_AudioStream_Result result;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_Start(mStream->stream.renderer);
    } else {
        result = OH_AudioCapturer_Start(mStream->stream.capturer);
    }
    LOGD("AAudioStream_requestStart, result: %d", result);
    return result;
}

ma_aaudio_result_t AAudioStream_requestStop(ma_AAudioStream *pStream)
{
    ma_AAudioStream_t *mStream = static_cast<ma_AAudioStream_t *>(pStream);
    if (mStream == nullptr) {
        return MA_AAUDIO_FORMAT_PCM_I16;
    }
    OH_AudioStream_Result result;
    if (mStream->direction == MA_AAUDIO_DIRECTION_OUTPUT) {
        result = OH_AudioRenderer_Stop(mStream->stream.renderer);
    } else {
        result = OH_AudioCapturer_Stop(mStream->stream.capturer);
    }
    LOGD("AAudioStream_requestStop, result: %d", result);
    return result;
}